package com.illumination.monitor.common.utils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;

import com.illumination.monitor.common.enums.ResultEnum;
import com.illumination.monitor.common.exception.BusinessException;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class BeanUtil extends BeanUtils {

	public static <T> T copy(Object source, Class<T> clazz) {
		if(source == null) return null;
		try {
			T t = clazz.newInstance();
			BeanUtils.copyProperties(source, t);
			return t;
		} catch (Exception e) {
			log.error("[工具类],对象属性拷贝异常:{}", e);
			return null;
		}
	}

	/** List对象属性拷贝 */
	public static final <T, E> void listCopyProperties(final Collection<E> source, final Collection<T> target,final Class<T> clazz) throws Exception {
		for (E e : source) {
			T t = clazz.newInstance();
			BeanUtils.copyProperties(e, t);
			target.add(t);
		}
	}

	/** List对象属性拷贝 忽略属性 */
	public static final <T, E> void listCopyProperties(final Collection<E> source, final Collection<T> target,final Class<T> clazz, String... ignoreProperties) throws Exception {
		for (E e : source) {
			T t = clazz.newInstance();
			BeanUtils.copyProperties(e, t, ignoreProperties);
			target.add(t);
		}
	}

	/** 对象转成二进制 */
	public @SneakyThrows static byte[] object2Byte(Object object) {
		try(   
				ByteArrayOutputStream byt = new ByteArrayOutputStream();
				ObjectOutputStream obj = new ObjectOutputStream(byt); 
			){
			obj.writeObject(object);
			return byt.toByteArray();
		}
	}

	/** 对象转成二进制 */
	public @SneakyThrows @SuppressWarnings("unchecked") static <T, T1> T1 byte2Objcet(byte[] bytes, Class<T1> clazz) {
		try(
				ByteArrayInputStream byteInt = new ByteArrayInputStream(bytes);
				ObjectInputStream objInt = new ObjectInputStream(byteInt);
			){
			T1 t = clazz.newInstance();
			t = (T1) objInt.readObject();
			return t;
		}
	}

	public @SneakyThrows static Map<String, Object> objectToMap(Object obj) {
		if (obj == null) 	throw new BusinessException(ResultEnum.BEAN_CONVERT_MAP);
		Map<String, Object> map = new HashMap<String, Object>();
		Field[] declaredFields = obj.getClass().getFields();
		for (Field field : declaredFields) {
			field.setAccessible(true);
			map.put(field.getName(),field.get(obj));
		}
		return map;
	}
	
	public @SneakyThrows static void copyIgnoreNull(Object source,Object target,String... ignoreProperties) {
		Field[] fields = FieldUtils.getAllFields(source.getClass());
		for (Field field : fields) {
			if("serialVersionUID".equals(field.getName())) continue;
			if(ArrayUtils.contains(ignoreProperties, field.getName())) continue;
			field.setAccessible(true);
			Object object = field.get(source);
//			if(object != null)  FieldUtils.writeField(field, target, object,true);
			if(object != null)  FieldUtils.writeDeclaredField(target, field.getName(), object, true);
		}
	}
	
	public @SneakyThrows static MultiValueMap<String, String> objectToMultiValueMap(Object obj) {
		if (obj == null) 	throw new BusinessException(ResultEnum.BEAN_CONVERT_MAP);
		MultiValueMap<String,String> map = new LinkedMultiValueMap<String,String>();
		Field[] declaredFields = obj.getClass().getDeclaredFields();
		for (Field field : declaredFields) {
			field.setAccessible(true);
			map.add(field.getName(),String.valueOf(field.get(obj)));
		}
		return map;
	}

}
